package top.milkbox.interceptor;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import top.milkbox.domain.User;
import top.milkbox.info.TokenUserInfo;

import javax.servlet.http.Cookie;

/**
 * 拦截器中用到的公共方法
 */
@Slf4j
@Component
public class BaseInterceptor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TokenUserInfo tokenUserInfo;

    /**
     * 子类中可能会用到
     */
    @Autowired
    protected ObjectMapper objectMapper;

    // 浏览器中存放token的键名
    protected final String COOKIE_TOKEN_NAME = "token";
    // 管理员的标志
    protected final String USER_ADMIN_FLAG = "true";


    /**
     * 验证用户是否在当前设备登录，即Redis中是否有用户的信息
     *
     * @param cookieList 当前设备或浏览器的cookie列表
     * @return 如果用户已登录则返回true，否则返回false
     */
    protected Boolean isUserLogin(Cookie[] cookieList) {
        if (cookieList == null || cookieList.length == 0) {
            log.debug("cookie为空");
            return false;
        }

        String token = getValueFromCookieList(COOKIE_TOKEN_NAME, cookieList);
        if (token == null) {
            log.debug("未在cookie中找到token");
            return false;
        }
        log.debug("设备的token：" + token);

        // 根据token判断用户是否已经登录
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        if (opsForValue.get(token) == null) {
            log.debug("当前设备未登录，token：" + token);
            return false;
        }

        // TODO 如果追求性能可以将这一个判断直接去掉
        String userId = token.split(tokenUserInfo.getTokenSplit())[1];
        if (opsForValue.get(generateUserKey(userId)) == null) { // 这种情况几乎不太可能出现
            log.debug("当前用户未登录，userId：" + userId);
            return false;
        }

        log.debug("redis中的用户信息存在");
        return true;
    }

    /**
     * 校验用户是否为管理员
     */
    // 淘汰注释
//    protected Boolean isAdmin(Cookie[] cookieList) {
//        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
//
//        // 获取到设备的token，一般不会为空，因为在此之前会被登录拦截器校验
//        String token = getValueFromCookieList(COOKIE_TOKEN_NAME, cookieList);
//        String userId = token.split(tokenUserInfo.getTokenSplit())[1]; // 解析出用户id
//        String userJson = opsForValue.get(generateUserKey(userId)); // 获取redis中的用户JSON信息
//        // 转为user对象
//        try {
//            User user = objectMapper.readValue(userJson, User.class);
//            if (USER_ADMIN_FLAG.equals(user.getUserAdmin())) {
//                log.debug("用户“" + user + "”是管理员");
//                return true;
//            } else {
//                log.debug("用户“" + user + "”不是是管理员");
//                return false;
//            }
//        } catch (JsonProcessingException e) {
//            log.error("JSON解析错误");
//            throw new RuntimeException(e);
//        }
//
//    }

    /**
     * 获取当前用户的角色id
     *
     * @param cookieList cookie列表
     * @return 整数
     */
    protected int getUserRole(Cookie[] cookieList) {
        int roleId = getUser(cookieList).getUserRoleId();
        log.debug("用户身份：" + roleId);
        return roleId;
    }

    /**
     * 从redis中获取user对象
     * 区别与userService中的方法，这里省去登录校验和token更新
     *
     * @param cookieList cookie列表
     * @return user对象
     */
    protected User getUser(Cookie[] cookieList) {
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        // 获取到设备的token，一般不会为空，因为在此之前会被登录拦截器校验
        String token = getValueFromCookieList(COOKIE_TOKEN_NAME, cookieList);
        String userId = token.split(tokenUserInfo.getTokenSplit())[1]; // 解析出用户id
        String userJson = opsForValue.get(generateUserKey(userId)); // 获取redis中的用户JSON信息
        try {
            return objectMapper.readValue(userJson, User.class);
        } catch (JsonProcessingException e) {
            log.error("JSON解析错误");
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过指定的cookie键获取这个键的值
     *
     * @param name       键名
     * @param cookieList cookie数组
     * @return 如果由则返回值，如果没有则返回空
     */
    protected String getValueFromCookieList(String name, Cookie[] cookieList) {
        for (Cookie cookie : cookieList) {
            if (name.equals(cookie.getName())) {
                return cookie.getValue();
            }
        }
        return null;
    }


    /**
     * 跟userService中的那个方法一样
     */
    protected String generateUserKey(String userId) {
        return tokenUserInfo.getUserPrefix() + tokenUserInfo.getUserSplit() + userId;
    }
}
